////////////////////////////////////////////////////////////////////////////////
//
// 宣言
//
////////////////////////////////////////////////////////////////////////////////
/**
 * グローバル変数
 */
// ポート番号
var port = 80;

// MySQL データベース名、ユーザ名、パスワード
var DB_NAME = "bubble";
var DB_USER = "app_user";
var DB_PASSWD = "app";

// テキスト情報のバッファ
var g_idea_map = {};

/*
 * モジュールの読み込み
 */
var express = require("express")
  , ejs = require("ejs")
  , io = require("socket.io")
  , sys = require("sys")
  , Client = require("mysql").Client;

////////////////////////////////////////////////////////////////////////////////
//
// MySQL
//
////////////////////////////////////////////////////////////////////////////////
/*
 * MySQLデータベースに接続しcallbackを呼び出す
 */
function mysql(callback) {
	var client = new Client();
	client.database = DB_NAME;
	client.user = DB_USER;
	client.password = DB_PASSWD;

	client.connect(function(err) {
		if (err) {
			throw err;
		}
		callback(client);
	});
}

////////////////////////////////////////////////////////////////////////////////
//
// メッセージ処理関数
//
////////////////////////////////////////////////////////////////////////////////
/**
 * テキスト情報を処理する
 * @param {object} client クライアントオブジェクト
 * @param {object} obj メッセージオブジェクト
 */
function message (client, obj) {
	var message = obj.message[0];
	var color = obj.message[1];
	var parent_id = obj.message[2];
	var msg = { message: [client.sessionId, 0, message, color, parent_id] };
	var msg_you = { message: ["you", 0, message, color, parent_id] };
	
	// mysql 実行（メッセージの登録）
	mysql(function(mysql_client) {
		mysql_client.query(
		   "INSERT INTO idea " +
		   "	(parent_idea_id, user_id, text, color) " + 
		   "	VALUES (?, ?, ?, ?)",
		   [parent_id, client.sessionId, message, color],
		   function(err, results) {
				if (err) {
					mysql_client.end();
					throw err;
				}
				if (!err) {
					mysql_client.end();
					
					// 結果IDを連携オブジェクトにセットする
					msg.message[1] = msg_you.message[1] = results.insertId;
					// メッセージをバッファに追加
					g_idea_map[String(results.insertId)] = msg;
					//クライアントに配信
					client.send(msg_you);
					// 他のクライアントに配信
					client.broadcast(msg);
				}
			}
		 );
	});
}

/**
 * イメージ情報を処理する
 * @param {object} client クライアントオブジェクト
 * @param {object} obj メッセージオブジェクト
 */
function image (client, obj) {
	var img = obj.image[0];
	var color = obj.image[1];
	var parent_id = obj.image[2];
	var msg = { image: [client.sessionId, 0, img, color, parent_id] };
	var msg_you = { image: ["you", 0, img, color, parent_id] };
	
	// mysql 実行（メッセージの登録）
	mysql(function(mysql_client) {
		mysql_client.query(
		   "INSERT INTO idea " +
		   "	(parent_idea_id, user_id, image, color) " + 
		   "	VALUES (?, ?, ?, ?)",
		   [parent_id, client.sessionId, img, color],
		   function(err, results) {
				if (err) {
					mysql_client.end();
					throw err;
				}
				if (!err) {
					mysql_client.end();
					
					// 結果IDを連携オブジェクトにセットする
					msg.image[1] = msg_you.image[1] = results.insertId;
					// メッセージをバッファに追加
					g_idea_map[String(results.insertId)] = 
						{ message: [client.sessionId, results.insertId, "[イメージ（バッファは未実装）]", color, parent_id] };
					//クライアントに配信
					client.send(msg_you);
					// 他のクライアントに配信
					client.broadcast(msg);
				}
			}
		 );
	});
}

/**
 * 関連付け情報を処理する
 * @param {object} client クライアントオブジェクト
 * @param {object} obj メッセージオブジェクト
 */
function linkage (client, obj) {
	var obj_id = obj.linkage[0];
	var parent_id = obj.linkage[1];
	
	// mysql 実行（関連付けの更新）
	mysql(function(mysql_client) {
		mysql_client.query(
		   "UPDATE idea " +
		   "SET parent_idea_id = ? " + 
		   "WHERE " +
		   "	idea_id = ?",
		   [parent_id, obj_id],
		   function(err, results) {
				if (err) {
					mysql_client.end();
					throw err;
				}
				if (!err) {
					mysql_client.end();
					
					// バッファの関連付けを変更
					g_idea_map[String(obj_id)].message[4] = parent_id;
					
					// 他のクライアントに配信
					client.broadcast(obj);
				}
			}
		 );
	});
}

////////////////////////////////////////////////////////////////////////////////
//
// HTTP
//
////////////////////////////////////////////////////////////////////////////////
/*
 * サーバの準備
 */
// サーバを作成
var app = express.createServer();

// 静的ファイルのフォルダ
app.configure(function(){
	app.use(express.staticProvider(__dirname + "/public"));
});
// ejsテンプレートを利用する
app.set("view engine", "ejs");
// レイアウトを利用しない
app.set("view options", {layout: false});

/*
 * GETリクエストを受け取る
 */
app.get("/", function(req, res){
	res.render("index", {locals: {port: port}});
});

/*
 * サーバを起動する
 */
app.listen(port);

////////////////////////////////////////////////////////////////////////////////
//
// WebSocket
//
////////////////////////////////////////////////////////////////////////////////
/*
 * WebSocketを起動する
 */
var io = io.listen(app);
  
/** 
 * クライアントの接続時
 */
io.on('connection', function(client){

	// クライアントに今までのメッセージ履歴（バッファ）を送信する
	client.send({ buffer: g_idea_map });
	// 他のクライアントに接続通知メッセージを送信する
	client.broadcast({ announcement: client.sessionId + ' connected' });

	/**
	 * クライアントからの受信時
	 */
	client.on('message', function(obj){
		// テキスト情報受信の場合
		if ("message" in obj) {
			message(client, obj);
		}
		// イメージ情報受信の場合
		else if ("image" in obj) {
			image(client, obj);
		}
		// 関連付け情報受信の場合
		else if ("linkage" in obj) {
			linkage(client, obj);
		}
	});

	/*
	 * クライアントの切断時
	 */
	client.on('disconnect', function(){
		// 他のクライアントに切断通知メッセージを送信する
		client.broadcast({ announcement: client.sessionId + ' disconnected' });
	});
});
